#include "vd_input.h"

/*
* module para
*/
vd_ssocket vd_input_ssock;

static int keyboard = 1;
module_param(keyboard, int, S_IRUGO);

static int mouse = 1;
module_param(mouse, int, S_IRUGO);

static int port = 20000;
module_param(port, int, S_IRUGO);

static int buff_size = 32;
module_param(buff_size, int, S_IRUGO);
/*
* struct cdev of "vd_inputoard"
*/
struct input_dev *vd_input_dev;
static struct platform_device *vd_input_plat_dev;

#define VD_KBD_SCANCODES 256

static const unsigned short vd_input_keycode[VD_KBD_SCANCODES] = {
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A, KEY_B,
	KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L,
	KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V,
	KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6,
	KEY_7, KEY_8, KEY_9, KEY_0, KEY_ENTER, KEY_ESC, KEY_BACKSPACE,
	KEY_TAB, KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE,
	KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON,
	KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, KEY_DOT, KEY_SLASH,
	KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6,
	KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_SYSRQ,
	KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP,
	KEY_DELETE, KEY_END, KEY_PAGEDOWN, KEY_RIGHT, KEY_LEFT, KEY_DOWN,
	KEY_UP, KEY_NUMLOCK, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS,
	KEY_KPPLUS, KEY_KPENTER, KEY_KP1, KEY_KP2, KEY_KP3, KEY_KP4, KEY_KP5,
	KEY_KP6, KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT, KEY_102ND,
	KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, KEY_F14, KEY_F15,
	KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20, KEY_F21, KEY_F22,
	KEY_F23, KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT, KEY_STOP,
	KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE,
	KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_KPCOMMA, KEY_RESERVED, KEY_RO, KEY_KATAKANAHIRAGANA , KEY_YEN,
	KEY_HENKAN, KEY_MUHENKAN, KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA,
	KEY_ZENKAKUHANKAKU, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
	KEY_RESERVED, KEY_RESERVED, KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT,
	KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT,
	KEY_RIGHTMETA, KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG,
	KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE,
	KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, KEY_SCROLLUP,
	KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP, KEY_SCREENLOCK, KEY_REFRESH,
	KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED
};

static int vd_reg_input_dev(void)
{
    int i = 0;
    int err = 0;

    vd_input_plat_dev = platform_device_register_simple("vd_input", -1, NULL, 0);

    if (IS_ERR(vd_input_dev)) {
        printk("vd_kyeboard_mouse_init: error\n");
        return PTR_ERR(vd_input_dev);
    }

    /* Allocate an input device data structure */
    vd_input_dev = input_allocate_device();

    if (!vd_input_dev) {
        printk("input_allocate_device() failed\n");
        return -ENOMEM;
    }

    vd_input_dev->name = DEVICE_NAME;

    if (keyboard)
    {
        /* Announce that the virtual mouse will generate what for keyboard*/
        vd_input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) | BIT(EV_SND) | BIT(EV_REP);
        vd_input_dev->ledbit[0] = BIT_MASK(LED_CAPSL) | BIT_MASK(LED_SLEEP) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL);
        vd_input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_CLICK);

        vd_input_dev->keycode = vd_input_keycode;
        vd_input_dev->keycodesize = sizeof(unsigned short);
        vd_input_dev->keycodemax = ARRAY_SIZE(vd_input_keycode);

        for (i=0; i<VD_KBD_SCANCODES; i++)
        {
            set_bit(vd_input_keycode[i], vd_input_dev->keybit);
        }
        clear_bit(KEY_RESERVED, vd_input_dev->keybit);
    }

    if (mouse)
    {
        /* Announce that the virtual mouse will generate what for mouse */
        vd_input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) | BIT(EV_REP);
        vd_input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
        vd_input_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
    }
    /* Register with the input subsystem */
    err = input_register_device(vd_input_dev);
	if (err) {
		input_free_device(vd_input_dev);
		return err;
	}

    printk("Virtual Keyboard_mouse initialized.\n");

    return 0;
}

static int vd_unreg_input_dev(void)
{
    /* Unregister from the input subsystem */
    input_unregister_device(vd_input_dev);

    /* Unregister driver */
    platform_device_unregister(vd_input_plat_dev);

    return 0;
}

static void vd_input_net_data_proc(char *buff, int size)
{
    int i = 0;

    if (size < sizeof(struct input_event))
    {
        printk("recv remote input_event error\n");
        return;
    }

    struct input_event *event_key = (struct input_event*)buff;

    for (i=0; i < size / sizeof(struct input_event); ++i)
    {
        /* Report relative coordinates via the event interface */
        input_event(vd_input_dev, event_key[i].type, event_key[i].code, event_key[i].value);
        input_sync(vd_input_dev);
    }
}

static int __init vd_input_init(void)
{
    int err = 0;

	printk("Initialize virtual kyeborad_mouse\n");

	vd_reg_input_dev();

	vd_input_ssock.proc_func = vd_input_net_data_proc;
	vd_input_ssock.buff_size = buff_size;
	vd_input_ssock.buff = kmalloc(vd_input_ssock.buff_size, GFP_KERNEL);

	if (vd_input_ssock.buff == NULL)
        return err;

	err = vd_start_server_udp_socket(&vd_input_ssock, port);

	if (err != 0)
    {
        printk("Creating kbdoard_mouse socket fails\n");
    }

	return err;
}

static void __exit vd_input_exit(void)
{
	vd_close_server_udp_socket(&vd_input_ssock);

	printk("vd close kerboard_mouse server_socket\n");

	kfree(vd_input_ssock.buff);

	vd_unreg_input_dev();

	printk("Unload virtual Keyboard_mouse\n");
}

module_init(vd_input_init);
module_exit(vd_input_exit);

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR( "lzhang" );
